﻿using UnityEngine;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using System;

/// <summary>
/// 资源打包工具窗口
/// </summary>
public class ResBuildWindow : EditorWindow
{
    static ResBuildWindow buildWindow;

    /// <summary>
    /// 资源平台列表
    /// </summary>
    static List<string> platformStrings = new List<string>();
    /// <summary>
    /// 当前资源平台索引
    /// </summary>
    static int nowPlatformIndex = 0;

    /// <summary>
    /// 是否处于焦点状态
    /// </summary>
    static bool isFocused = false;
    /// <summary>
    /// 数据是否加载
    /// </summary>
    static bool isLoadData = false;

    /// <summary>
    /// 预制体路径 "Asset/Prefabs/";
    /// </summary>
    static string prefabPath;

    /// <summary>
    /// Resources 路径 "Assets/Resources/";
    /// </summary>
    static string resPath;

    /// <summary>
    /// ab文件的根目录 ProjectName/Resources
    /// </summary>
    static string abPathRoot;

    /// <summary>
    /// AB文件路径
    /// </summary>        
    static string abPath;

    /// <summary>
    /// 所有的子工程
    /// </summary>
    static List<string> resConfigStrings = new List<string>();

    static string resConfigPath;
    static string versionFilePath;
    /// <summary>
    /// 资源配置
    /// </summary>
    static ResConfig resConfig = new ResConfig();
    /// <summary>
    /// 版本信息
    /// </summary>
    static Version versionInfo = new Version();
    static Project nowProject = null;
    static int projectIndex = 0;

    private static DateTime m_startTime = new DateTime(1970, 1, 1).ToLocalTime();
    private static int _offset = 0;
    public static int iTimeDifference = 0;

    [MenuItem("工具/资源打包工具", false, 0)]
    static void Init()
    {
        buildWindow = (ResBuildWindow)EditorWindow.GetWindow(typeof(ResBuildWindow), false, "打包工具", true);
        buildWindow.Show();
        LoadData();
    }

    /// <summary>
    /// 获得焦点
    /// </summary>
    private void OnFocus()
    {
        isFocused = true;
        if (!isLoadData)
        {
            LoadData();
        }
    }

    /// <summary>
    /// 丢失焦点
    /// </summary>
    private void OnLostFocus()
    {
        isFocused = false;
        isLoadData = false;
    }

    /// <summary>
    /// 加载数据
    /// </summary>
    static void LoadData()
    {
        prefabPath = "Assets/Prefabs/";
        resPath = "Assets/Resources/";
        abPathRoot = Application.dataPath + "/../../Resources/";

        if (Directory.Exists(abPathRoot))
        {
            Directory.CreateDirectory(abPathRoot);
        }

        platformStrings.Clear();
        platformStrings.Add(BuildTarget.Android.ToString());
        platformStrings.Add(BuildTarget.iOS.ToString());
        platformStrings.Add(BuildTarget.StandaloneWindows.ToString());
        platformStrings.Add(BuildTarget.StandaloneOSX.ToString());
        platformStrings.Add(BuildTarget.StandaloneLinux64.ToString());

        versionFilePath = Application.dataPath + "/Editor/ResBuilder/Version.txt";
        versionInfo = ReadVersionInfo(versionFilePath);

        resConfigPath = Application.dataPath + "/Editor/ResBuilder/ResConfig.txt";
        resConfig = GetResConfig(resConfigPath);

        resConfigStrings.Clear();
        foreach (Project project in resConfig.Projects)
        {
            resConfigStrings.Add(project.description);
        }
        projectIndex = resConfig.projectIndex;
        nowPlatformIndex = resConfig.platformIndex;

        nowProject = resConfig.Projects[projectIndex];

        isLoadData = true;
    }

    void OnGUI()
    {
        if (!isFocused)
        {
            return;
        }

        EditorGUILayout.Space();
        if (GUILayout.Button("设置资源的AB名"))
        {
            SetAllAbNames();
        }
        EditorGUILayout.Space();

        EditorGUILayout.Space();
        if (GUILayout.Button("打印所有的AB包名字"))
        {
            PrintABsNames();
        }
        EditorGUILayout.Space();

        EditorGUILayout.Space();
        if (GUILayout.Button("清除所有AB包的名字"))
        {
            ClearABsName();
        }
        EditorGUILayout.Space();

        EditorGUILayout.Space();
        GUILayout.Label("子项目参数");
        projectIndex = GUILayout.Toolbar(projectIndex, resConfigStrings.ToArray());
        nowProject = resConfig.Projects[projectIndex];
        nowProject.id = EditorGUILayout.IntField("id:", nowProject.id);
        nowProject.name = EditorGUILayout.TextField("name:", nowProject.name);
        nowProject.isMain = EditorGUILayout.Toggle("isMain:", nowProject.isMain);
        nowProject.isInPackage = EditorGUILayout.Toggle("isInPackage:", nowProject.isInPackage);
        nowProject.description = EditorGUILayout.TextField("description:", nowProject.description);

        EditorGUILayout.Space();
        EditorGUILayout.Space();
        GUILayout.Label("选择打包平台");
        nowPlatformIndex = GUILayout.Toolbar(nowPlatformIndex, platformStrings.ToArray());
        EditorGUILayout.Space();

        EditorGUILayout.Space();
        GUILayout.Label("设置版本号");
        versionInfo.AppVersion = EditorGUILayout.IntField("AppVersion:", versionInfo.AppVersion);
        versionInfo.AppUrl = EditorGUILayout.TextField("ResUrl:", versionInfo.AppUrl);
        EditorGUILayout.Space();

        EditorGUILayout.Space();
        if (GUILayout.Button("保存版本信息"))
        {
            SaveVersionInfo(versionInfo, versionFilePath);
        }
        EditorGUILayout.Space();

        EditorGUILayout.Space();
        if (GUILayout.Button("打包所选平台资源"))
        {
            var time = GetNowTimeStamp(); 
            EditorUtility.DisplayProgressBar("打包所选平台资源", "打包所选平台资源", 0);
            BuildTarget bt = (BuildTarget)Enum.Parse(typeof(BuildTarget), platformStrings[nowPlatformIndex]);
            string abPath = abPathRoot + GetPlatformName(bt) + "/";
            if (!Directory.Exists(abPath))
            {
                Directory.CreateDirectory(abPath);
            }
            DirectoryInfo di = new DirectoryInfo(abPath);
            foreach (FileInfo fi in di.GetFiles())
            {
                fi.Delete();
            } 
            BuildPipeline.BuildAssetBundles(abPath, BuildAssetBundleOptions.None, bt);
            CreateABMD5List.Execute(abPath);
            EditorUtility.ClearProgressBar();
            var dtTime = GetPassTime(time);
            Debug.Log(string.Format("打包资源用时：{0}分{1}秒", dtTime.Minutes, dtTime.Seconds));
        }
        EditorGUILayout.Space();

        EditorGUILayout.Space();
        if (GUILayout.Button("拷贝所选平台资源到客户端工程"))
        {
            EditorUtility.DisplayProgressBar("拷贝资源到客户端工程", "拷贝资源到客户端工程", 0);
            string targetPath = Application.dataPath + "/../../Client/Assets/StreamingAssets/";
            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }

            DirectoryInfo dit = new DirectoryInfo(targetPath);
            foreach (FileInfo fi in dit.GetFiles())
            {
                fi.Delete();
            }

            BuildTarget bt = (BuildTarget)Enum.Parse(typeof(BuildTarget), platformStrings[nowPlatformIndex]);

            string abPath = abPathRoot + GetPlatformName(bt) + "/";
            DirectoryInfo di = new DirectoryInfo(abPath);

            //如windows.t、windows.manifest.t文件
            foreach (FileInfo fi in di.GetFiles())
            {
                //if (fi.Name.StartsWith(GetPlatformName(bt).ToLower()))
                //{
                    fi.CopyTo(targetPath + fi.Name);
                //}
            }
            EditorUtility.ClearProgressBar();
        }
    }

    /// <summary>
    /// 设置资源的AB名，这里可以处理资源文件的依赖关系，比如可以把一个文件的图片打成一个ab包，各种别的选择……
    /// </summary>
    void SetAllAbNames()
    {
        EditorUtility.DisplayProgressBar("设置预制的AB名", "设置预制的AB名", 0);

        var time = GetNowTimeStamp();

        foreach (Project p in resConfig.Projects)
        {
            SetSubProjectABsName(p.name);
        }
        var dtTime = GetPassTime(time);

        Debug.Log(string.Format("设置用时：{0}分{1}秒", dtTime.Minutes, dtTime.Seconds));
        AssetDatabase.Refresh();
        EditorUtility.ClearProgressBar(); 
    }

    /// <summary>
    /// 打印所有的AB包名字
    /// </summary>
    void PrintABsNames()
    {
        EditorUtility.DisplayProgressBar("打印所有的AB包名字", "打印所有的AB包名字", 0);
        //获取所有设置的AssetBundle 
        string[] names = AssetDatabase.GetAllAssetBundleNames();
        foreach (string name in names)
        {
            Debug.Log("AB名: " + name);
        }
        AssetDatabase.Refresh();
        EditorUtility.ClearProgressBar();
    }

    /// <summary>
    /// 清除所有AB包的名字
    /// </summary>
    void ClearABsName()
    {
        EditorUtility.DisplayProgressBar("清除", "清除所有AB包的名字", 0);
        string[] ABsNames = AssetDatabase.GetAllAssetBundleNames();
        for (int j = 0; j < ABsNames.Length; j++)
        {
            AssetDatabase.RemoveAssetBundleName(ABsNames[j], true);
        }
        //刷新资源
        AssetDatabase.Refresh();
        EditorUtility.ClearProgressBar();
    }

    private static void SetSubProjectABsName(string projectName)
    {
        //设置ResourceLib文件夹下资源文件bundle归属
        SetABsNameByRootFolder(resPath + projectName + "/Animation/");
        SetABsNameByRootFolder(resPath + projectName + "/AnimatorController/");
        SetABsNameByRootFolder(resPath + projectName + "/Animator/");
        SetABsNameByAllFloder(resPath + projectName + "/Atlas/");
        SetABsNameByRootFolder(resPath + projectName + "/Audio/");
        SetABsNameByRootFolder(resPath + projectName + "/Data/");
        SetABsNameByRootFolder(resPath + projectName + "/Effect/");
        SetABsNameByRootFolder(resPath + projectName + "/Font/");
        SetABsNameByRootFolder(resPath + projectName + "/Material/");
        SetABsNameByRootFolder(resPath + projectName + "/Model/");
        SetABsNameByRootFolder(resPath + projectName + "/Shader/");
        SetABsNameByRootFolder(resPath + projectName + "/Textures/");

        //设置Prefabs文件夹下资源文件bundle归属
        SetABsNameByRootFolder(prefabPath + projectName + "/Effect/");
        SetABsNameByRootFolder(prefabPath + projectName + "/Model/");
        SetABsNameByRootFolder(prefabPath + projectName + "/Other/");
        SetABsNameByRootFolder(prefabPath + projectName + "/Scenes/");
        SetABsNameByRootFolder(prefabPath + projectName + "/UI/");
        SetABsNameByRootFolder(prefabPath + projectName + "/Fx/");
    }

    /// <summary>
    /// 这个文件夹下 每一个子目录都会单独打包
    /// </summary>
    /// <param name="folder"></param>
    /// <param name="abName"></param>
    private static void SetABsNameByAllFloder(string folder, string abName = null)
    {
        if (!Directory.Exists(folder))
        {
            Debug.Log("没有文件夹: " + folder);
            return;
        }

        var dirArr = Directory.GetDirectories(folder);

        if (0 == dirArr.Length)
        {
            string[] pathArr = GetFiles(folder, false);

            if (pathArr == null || pathArr.Length == 0)
            {
                Debug.Log("空文件夹: " + folder);
                return;
            }

            SetABsNameByFiles(pathArr, abName);
        }

        for (int i = 0; i < dirArr.Length; i++)
        {
            SetABsNameByAllFloder(dirArr[i], dirArr[i]);
        }
    }

    /// <summary>
    /// 就这个文件夹下 搜索所有子目录
    /// </summary>
    /// <param name="folder"></param>
    /// <param name="abName"></param>
    private static void SetABsNameByRootFolder(string folder, string abName = null)
    {
        if (!Directory.Exists(folder))
        {
            Debug.Log("没有文件夹: " + folder);
            return;
        }

        string[] pathArr = GetFiles(folder, true);

        if (pathArr == null || pathArr.Length == 0)
        {
            Debug.Log("空文件夹: " + folder);
            return;
        }
        SetABsNameByFiles(pathArr, abName);
    }

    private static void SetABsNameByFiles(string[] pathArr, string abName)
    {
        for (int j = 0; j < pathArr.Length; j++)
        {
            if (pathArr[j].Contains(".DS_Store") || Path.GetExtension(pathArr[j]) == ".meta")
            {
                continue;
            }

            var progress = (j + 1f) / pathArr.Length;

            EditorUtility.DisplayProgressBar("更新子项目的ABName", pathArr[j], progress);

            var importer = AssetImporter.GetAtPath(pathArr[j]);
            if (importer != null)
            {
                var newName = abName == null ? pathArr[j] : abName;
                var index = newName.IndexOf("Assets/Resources/");
                var beginIndex = index == -1 ?
                    (("Assets/Prefabs/").Length) :
                    (("Assets/Resources/").Length);

                newName = Path.HasExtension(newName) ? newName.Substring(beginIndex, newName.IndexOf('.') - beginIndex) : newName.Substring(beginIndex);
                importer.assetBundleName = FormatPath(newName);
                AssetDatabase.WriteImportSettingsIfDirty(pathArr[j]);
            }
        }
    }

    public static string FormatPath(string path)
    {
        if (string.IsNullOrEmpty(path))
        {
            return string.Empty;
        }
        path = path.Replace('\\', '.');
        return path.Replace('/', '.');
    }

    private static ResConfig GetResConfig(string resConfigPath)
    {
        ResConfig resConfig = new ResConfig();
        StreamReader sr = new StreamReader(resConfigPath);
        string projectConfigString = sr.ReadToEnd();
        sr.Close();
        EditorJsonUtility.FromJsonOverwrite(projectConfigString, resConfig);
        return resConfig;
    }

    static Version ReadVersionInfo(string path)
    {
        Version versionInfo = new Version();
        StreamReader dsr = new StreamReader(path);
        string dvfs = dsr.ReadToEnd();
        dsr.Close();
        EditorJsonUtility.FromJsonOverwrite(dvfs, versionInfo);
        return versionInfo;
    }

    static void SaveVersionInfo(Version versionInfo, string path)
    {
        string versionInfoString = EditorJsonUtility.ToJson(versionInfo);
        StreamWriter sw = new StreamWriter(path);
        sw.Write(versionInfoString);
        sw.Close();
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 获取目录下的所有对象路径，去掉了.meta
    /// </summary>
    /// <param name="path">目录路径</param>
    /// <param name="recursive">是否递归获取</param>
    /// <returns></returns>
    public static string[] GetFiles(string path, bool recursive = true)
    {
        var resultList = new List<string>();
        var dirArr = Directory.GetFiles(path, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
        for (int i = 0; i < dirArr.Length; i++)
        {
            if (Path.GetExtension(dirArr[i]) != ".meta")
            {
                resultList.Add(dirArr[i].Replace('\\', '/'));
            }
        }
        return resultList.ToArray();
    }

    /// <summary>
    /// 获取平台名
    /// </summary>
    /// <param name="bt"></param>
    /// <returns></returns>
    private static string GetPlatformName(BuildTarget bt)
    {
        switch (bt)
        {
            case BuildTarget.Android:
            case BuildTarget.iOS:
                return bt.ToString();
            case BuildTarget.StandaloneWindows:
            case BuildTarget.StandaloneWindows64:
                return "Windows";
            case BuildTarget.StandaloneOSX:
                return "OSX";
            default:
                Debug.LogError("不支持的打包渠道");
                return "";
        }
    }

    /// <summary>
    /// 获取从指定时间到现在的时间差
    /// </summary>
    /// <param name="startStamp"></param>
    /// <returns></returns>
    public static TimeSpan GetPassTime(int startStamp)
    {
        return GetNowTime() - GetTime(startStamp);
    }

    public static int GetTimeStamp(DateTime time)
    {
        return (int)(time - m_startTime).TotalSeconds;
    }

    public static DateTime GetNowTime()
    {
        return DateTime.Now.AddSeconds(_offset);
    }

    public static int GetNowTimeStamp()
    {
        return GetTimeStamp(GetNowTime());
    }

    public static DateTime GetTime(int timeStamp)
    {
        return m_startTime.AddSeconds(timeStamp);
    }
}